package com.icongyou.enterprise.talent_pool.service;

import com.icongyou.enterprise.data_aggregation.entity.AssignmentEntity;
import com.icongyou.enterprise.data_aggregation.service.DataAggregationService;
import com.icongyou.enterprise.talent_pool.mapper.AssignmentTagMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.math.BigDecimal;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class AssignmentWeightServiceTest {

    @Mock
    private AssignmentTagMapper assignmentTagMapper;

    @Mock
    private DataAggregationService dataAggregationService;

    @InjectMocks
    private AssignmentWeightService assignmentWeightService;

    private String assignmentId;
    private AssignmentEntity assignment;

    @BeforeEach
    void setUp() {
        assignmentId = "assignment-123";

        assignment = new AssignmentEntity();
        assignment.setAssignmentId(assignmentId);
        assignment.setCourseId("course-456");
        assignment.setAssignmentName("Test Assignment");
        assignment.setFullScore(new BigDecimal("100.0"));
    }

    @Test
    void calculateAssignmentImportanceWeight_ValidAssignment_ShouldReturnCorrectWeight() {
        // Arrange
        when(dataAggregationService.getAssignmentInfo(assignmentId)).thenReturn(assignment);
        when(assignmentTagMapper.getCourseTotalScore("course-456")).thenReturn(1000.0);

        // Act
        Double result = assignmentWeightService.calculateAssignmentImportanceWeight(assignmentId);

        // Assert
        assertNotNull(result);
        assertEquals(0.37, result, 0.01); // 0.3 + (100/1000 * 0.7) = 0.37
        verify(dataAggregationService).getAssignmentInfo(assignmentId);
        verify(assignmentTagMapper).getCourseTotalScore("course-456");
    }

    @Test
    void calculateAssignmentImportanceWeight_AssignmentNotFound_ShouldReturnDefaultWeight() {
        // Arrange
        when(dataAggregationService.getAssignmentInfo(assignmentId)).thenReturn(null);

        // Act
        Double result = assignmentWeightService.calculateAssignmentImportanceWeight(assignmentId);

        // Assert
        assertEquals(1.0, result);
    }

    @Test
    void calculateAssignmentImportanceWeight_NullCourseId_ShouldReturnDefaultWeight() {
        // Arrange
        assignment.setCourseId(null);
        when(dataAggregationService.getAssignmentInfo(assignmentId)).thenReturn(assignment);

        // Act
        Double result = assignmentWeightService.calculateAssignmentImportanceWeight(assignmentId);

        // Assert
        assertEquals(1.0, result);
    }

    @Test
    void calculateAssignmentImportanceWeight_ZeroFullScore_ShouldReturnDefaultWeight() {
        // Arrange
        assignment.setFullScore(BigDecimal.ZERO);
        when(dataAggregationService.getAssignmentInfo(assignmentId)).thenReturn(assignment);

        // Act
        Double result = assignmentWeightService.calculateAssignmentImportanceWeight(assignmentId);

        // Assert
        assertEquals(1.0, result);
    }

    @Test
    void calculateAssignmentImportanceWeight_NullFullScore_ShouldReturnDefaultWeight() {
        // Arrange
        assignment.setFullScore(null);
        when(dataAggregationService.getAssignmentInfo(assignmentId)).thenReturn(assignment);

        // Act
        Double result = assignmentWeightService.calculateAssignmentImportanceWeight(assignmentId);

        // Assert
        assertEquals(1.0, result);
    }

    @Test
    void calculateAssignmentImportanceWeight_ZeroCourseTotalScore_ShouldReturnDefaultWeight() {
        // Arrange
        when(dataAggregationService.getAssignmentInfo(assignmentId)).thenReturn(assignment);
        when(assignmentTagMapper.getCourseTotalScore("course-456")).thenReturn(0.0);

        // Act
        Double result = assignmentWeightService.calculateAssignmentImportanceWeight(assignmentId);

        // Assert
        assertEquals(1.0, result);
    }

    @Test
    void calculateAssignmentImportanceWeight_NullCourseTotalScore_ShouldReturnDefaultWeight() {
        // Arrange
        when(dataAggregationService.getAssignmentInfo(assignmentId)).thenReturn(assignment);
        when(assignmentTagMapper.getCourseTotalScore("course-456")).thenReturn(null);

        // Act
        Double result = assignmentWeightService.calculateAssignmentImportanceWeight(assignmentId);

        // Assert
        assertEquals(1.0, result);
    }

    @Test
    void calculateAssignmentImportanceWeight_ExceptionThrown_ShouldReturnDefaultWeight() {
        // Arrange
        when(dataAggregationService.getAssignmentInfo(assignmentId)).thenThrow(new RuntimeException("Service error"));

        // Act
        Double result = assignmentWeightService.calculateAssignmentImportanceWeight(assignmentId);

        // Assert
        assertEquals(1.0, result);
    }

    @Test
    void calculateAssignmentImportanceWeight_HighScoreRatio_ShouldReturnHigherWeight() {
        // Arrange
        assignment.setFullScore(new BigDecimal("500.0"));
        when(dataAggregationService.getAssignmentInfo(assignmentId)).thenReturn(assignment);
        when(assignmentTagMapper.getCourseTotalScore("course-456")).thenReturn(1000.0);

        // Act
        Double result = assignmentWeightService.calculateAssignmentImportanceWeight(assignmentId);

        // Assert
        assertEquals(0.65, result, 0.01); // 0.3 + (500/1000 * 0.7) = 0.65
    }

    @Test
    void calculateAssignmentImportanceWeight_LowScoreRatio_ShouldReturnLowerWeight() {
        // Arrange
        assignment.setFullScore(new BigDecimal("10.0"));
        when(dataAggregationService.getAssignmentInfo(assignmentId)).thenReturn(assignment);
        when(assignmentTagMapper.getCourseTotalScore("course-456")).thenReturn(1000.0);

        // Act
        Double result = assignmentWeightService.calculateAssignmentImportanceWeight(assignmentId);

        // Assert
        assertEquals(0.307, result, 0.01); // 0.3 + (10/1000 * 0.7) = 0.307
    }
}